// 处理用户使用自定义组件
package fgin

import (
	"context"
	"encoding/json"
	"errors"
	"sync"

	"github.com/gin-gonic/gin"
	"google.golang.org/grpc"
)

// 全局插件记录
var (
	FGINHTTPPLUGSMAP           = map[string]FginHttpPlugsInterface{}          // http自定义组件
	FGINGRPCMIDDPLUGSLS        = []string{}                                   // grpc server拦截器注册顺序
	FGINGRPCMIDDPLUGSMAP       = map[string]FginGrpcMiddPlugsInterface{}      // grpc server拦截器自定义组件
	FGINGRPCCLIENTMIDDPLUGSLS  = []string{}                                   // grpc client端拦截器注册顺序
	FGINGRPCCLIENTMIDDPLUGSMAP = map[string]FginGrpcClientMiddPlugInterface{} // grpc client端拦截器
	FGINGRPCPLUGSMAP           = map[string]FginGrpcPlugsInterface{}          // grpc自定义组件
)

type FginHttpPlugsInterface interface {
	// 给到router，可以实现中间件，也可以实现其他组件
	Start(router *gin.Engine, logger *FginSugaredLogger)
}

type FginGrpcMiddPlugsInterface interface {
	// grpc server拦截器给到ctx
	Start(ctx context.Context, req any, info *grpc.UnaryServerInfo, logger *FginSugaredLogger) (context.Context, error)
	// grpc server 方法执行后
	AfterStart(ctx context.Context, req any, info *grpc.UnaryServerInfo, grpcErr error, logger *FginSugaredLogger) error
}

type FginGrpcClientMiddPlugInterface interface {
	// grpc client端拦截器
	Start(ctx context.Context, method string, req, reply any, logger *FginSugaredLogger) (context.Context, error)
	// 方法执行后
	AfterStart(ctx context.Context, method string, req, reply any, grpcErr error, logger *FginSugaredLogger) error
}

type FginGrpcPlugsInterface interface {
	// grpc自定义组件
	Start(logger *FginSugaredLogger)
}

// 注册http组件
func RegisteHttpPlug(plugName string, plugObj FginHttpPlugsInterface) {
	var mu sync.Mutex
	mu.Lock()
	defer mu.Unlock()
	FGINHTTPPLUGSMAP[plugName] = plugObj
}

// http自定义组件运行
func PlugsHttpStart(router *gin.Engine) {
	var wg sync.WaitGroup
	for plugName, obj := range FGINHTTPPLUGSMAP {
		// 异步启动
		wg.Add(1)
		go func(s string, o FginHttpPlugsInterface) {
			defer wg.Done()
			// 获取配置
			c, err := FginGetPlugConfig(s)
			if err != nil {
				panic(err)
			}
			// 反序列化
			if err := FginBindPlugConfig(c, &o); err != nil {
				panic(err)
			}
			// 执行插件
			o.Start(router, logSuger)
		}(plugName, obj)
	}
	wg.Wait()
}

// 注册grpc拦截器组件
func RegisteGrpcMiddPlug(plugName string, plugObj FginGrpcMiddPlugsInterface) {
	var mu sync.Mutex
	mu.Lock()
	defer mu.Unlock()
	FGINGRPCMIDDPLUGSLS = append(FGINGRPCMIDDPLUGSLS, plugName)
	FGINGRPCMIDDPLUGSMAP[plugName] = plugObj
}

// grpc拦截器自定义组件运行
func PlugsGrpcMiddStart(ctx context.Context, req any, info *grpc.UnaryServerInfo) (context.Context, error) {
	for _, plugName := range FGINGRPCMIDDPLUGSLS {
		obj := FGINGRPCMIDDPLUGSMAP[plugName]
		c, err := FginGetPlugConfig(plugName)
		if err != nil {
			panic(err)
		}
		// 反序列化
		if err := FginBindPlugConfig(c, &obj); err != nil {
			panic(err)
		}
		// 执行插件
		ctx, err = obj.Start(ctx, req, info, logSuger)
		if err != nil {
			return ctx, err
		}
	}
	return ctx, nil
}

// grpc拦截器自定义组件运行后 接着运行
func PlugsGrpcMiddAfterStart(ctx context.Context, req any, info *grpc.UnaryServerInfo, grpcErr error) error {
	plugsNum := len(FGINGRPCMIDDPLUGSLS)
	for i := plugsNum - 1; i >= 0; i-- {
		plugName := FGINGRPCMIDDPLUGSLS[i]
		obj := FGINGRPCMIDDPLUGSMAP[plugName]
		c, err := FginGetPlugConfig(plugName)
		if err != nil {
			panic(err)
		}
		// 反序列化
		if err := FginBindPlugConfig(c, &obj); err != nil {
			panic(err)
		}
		// 执行插件
		if err = obj.AfterStart(ctx, req, info, grpcErr, logSuger); err != nil {
			return err
		}
	}
	return nil
}

// 注册grpc client拦截器组件
func RegisteGrpcClientMiddPlug(plugName string, plugObj FginGrpcClientMiddPlugInterface) {
	var mu sync.Mutex
	mu.Lock()
	defer mu.Unlock()
	FGINGRPCCLIENTMIDDPLUGSLS = append(FGINGRPCCLIENTMIDDPLUGSLS, plugName)
	FGINGRPCCLIENTMIDDPLUGSMAP[plugName] = plugObj
}

// grpc client 中间件拦截器运行
func PlugsGrpcClientMiddStart(ctx context.Context, method string, req, reply any) (context.Context, error) {
	for _, plugName := range FGINGRPCCLIENTMIDDPLUGSLS {
		obj := FGINGRPCCLIENTMIDDPLUGSMAP[plugName]
		c, err := FginGetPlugConfig(plugName)
		if err != nil {
			panic(err)
		}
		// 反序列化
		if err := FginBindPlugConfig(c, &obj); err != nil {
			panic(err)
		}
		// 执行插件
		ctx, err = obj.Start(ctx, method, req, reply, logSuger)
		if err != nil {
			return ctx, err
		}
	}
	return ctx, nil
}

// grpc client 中间件拦截器运行 运行后
func PlugsGrpcClientMiddAfterStart(ctx context.Context, method string, req, reply any, grpcErr error) error {
	plugsNum := len(FGINGRPCCLIENTMIDDPLUGSLS)
	for i := plugsNum - 1; i >= 0; i-- {
		plugName := FGINGRPCCLIENTMIDDPLUGSLS[i]
		obj := FGINGRPCCLIENTMIDDPLUGSMAP[plugName]
		c, err := FginGetPlugConfig(plugName)
		if err != nil {
			panic(err)
		}
		// 反序列化
		if err := FginBindPlugConfig(c, &obj); err != nil {
			panic(err)
		}
		// 执行插件
		if err = obj.AfterStart(ctx, method, req, reply, grpcErr, logSuger); err != nil {
			return err
		}
	}
	return nil
}

// 注册grpc组件
func RegisteGrpcPlug(plugName string, plugObj FginGrpcPlugsInterface) {
	var mu sync.Mutex
	mu.Lock()
	defer mu.Unlock()
	FGINGRPCPLUGSMAP[plugName] = plugObj
}

// grpc自定义组件运行
func PlugsGrpcStart() {
	var wg sync.WaitGroup
	for plugName, obj := range FGINGRPCPLUGSMAP {
		// 异步启动
		wg.Add(1)
		go func(s string, o FginGrpcPlugsInterface) {
			// 获取配置
			defer wg.Done()
			c, err := FginGetPlugConfig(s)
			if err != nil {
				panic(err)
			}
			// 反序列化
			if err := FginBindPlugConfig(c, &o); err != nil {
				panic(err)
			}
			// 执行插件
			o.Start(logSuger)
		}(plugName, obj)
	}
	wg.Wait()
}

// 获取自定义组件的配置
func FginGetPlugConfig(plugName string) (any, error) {
	if v, ok := fginConfig.Plugs[plugName]; ok {
		return v, nil
	}
	return nil, errors.New(plugName + "没有配置")
}

// 反序列化到自定义组件对象
func FginBindPlugConfig(plugConfig any, plugObj any) error {
	// 将配置反序列化
	c1, err := json.Marshal(plugConfig)
	if err != nil {
		return err
	}
	if err := json.Unmarshal(c1, plugObj); err != nil {
		return err
	}
	return nil
}
